Evolution of sequence features
Build datasets
Sequence IDs, species and strain information.
Adhesin prediction results
FungalRV threshold: 0.51; FaaPred using ACHM model with the recommended -0.8 threshold.
GPI-anchor prediction (including signal peptide)
GPI-anchored proteins are characterized by an N-terminal signal peptide, which would direct the protein to the secretary pathway, and a C-terminal GPI-anchor peptide, which would be cleaved and replaced by the GPI-anchor, allowing the protein to be tethered to the cell wall. For signal peptide, I used SignalP server. Its latest version is 5.0. But I also ran the sequences through their 4.1 version, with two settings. The results of the latter two are almost identical, except for one sequence “XP_024711350.1”, which is only included in the sensitive version, and has a probability lower than 0.5. For GPI-anchor prediction, I used the PredGPI server. For signal peptide prediction, I used the SignalP 5.0 server
sps.list <- c("Cauris","Cpseudohaemulonis","Chaemuloni","Dhansenii")
seqInfo <- read_tsv("output/seq-feature/cauris-renamed-seqinfo.tsv", comment = "#", col_types = "cccci") %>%
mutate(species_id = factor(species, levels = sps.list), species = NULL)
Adhesin prediction
frv.th = 0.511 # recommended FungalRV score threshold
frv <- read_tsv("output/seq-feature/cauris-renamed-fungalrv.txt", skip = 3, col_names = c("name","frv.score"), col_types = "cd") %>%
mutate(name = str_sub(name, 2), frv.pred = frv.score > frv.th)
faa <- read_tsv("output/seq-feature/cauris-renamed-faapred.txt", col_names = c("name","faa.score","faa.pred"), col_types = "cdc") %>%
mutate(faa.pred = ifelse(faa.pred == "Adhesin", TRUE, FALSE))
if("frv.score" %in% names(seqInfo))
seqInfo <- select(seqInfo, -frv.score, -frv.pred, -faa.score, -faa.pred)
seqInfo <- seqInfo %>% left_join(frv) %>% left_join(faa)
Joining, by = "name"
Joining, by = "name"
seqInfo %>%
group_by(species_id, strain) %>%
summarize(n = n(), fungalRV = sum(frv.score > 0.511), faapred = sum(faa.pred, na.rm = T),
both = sum(frv.score > 0.511 & faa.pred))
`summarise()` has grouped output by 'species_id'. You can override using the `.groups` argument.
SignalP and GPI prediction
# Signal peptide
gff.names <- c("id", "source", "name", "start", "end", "prob", "na1", "na2", "na3")
signalp5 <- read_tsv("output/seq-feature/cauris-renamed-signalp5.gff3", comment = "#", col_names = gff.names, col_types = "ccciidccc")
if("signalp" %in% names(seqInfo))
seqInfo <- select(seqInfo, -signalp)
seqInfo <- left_join(seqInfo, select(signalp5, name = id, prob), by = c("name" = "name")) %>%
mutate(signalp = !is.na(prob)) %>% select(-prob)
tmp <- read_delim("output/seq-feature/cauris-renamed-predgpi.txt", delim = "|", col_names = c("name","fp","omega"))
── Column specification ───────────────────────────────────────────────────────────────────────────────────
cols(
name = col_character(),
fp = col_character(),
omega = col_character()
)
pred.gpi <- tmp %>%
mutate(name = str_sub(name, 2, -2), # remove > and the trailing space
fp = as.numeric(str_sub(fp, 9, -2)), # extract the numeric part
is.gpi = fp <= 0.01, # based on the cutoff of the PredGPI server (prob < 99% -> not GPI-anchored)
omega = str_sub(omega, 8),
cleaveRes = str_sub(omega, 1, 1),
cleavePos = as.integer(str_sub(omega, 3)),
) %>%
left_join(select(seqInfo, name, length), by = c("name" = "name"))
# remove the column if it already exists
if("pred.gpi" %in% names(seqInfo))
seqInfo <- select(seqInfo, -pred.gpi)
seqInfo <- left_join(seqInfo, select(pred.gpi, name, pred.gpi = is.gpi), by = c("name"="name"))
seqInfo %>%
group_by(species_id, strain) %>%
summarize(Total = n(), SignalP = sum(signalp), GPI_Pred = sum(pred.gpi), Both = sum(signalp & pred.gpi))
`summarise()` has grouped output by 'species_id'. You can override using the `.groups` argument.
write_tsv(seqInfo, "output/seq-feature/R-seqinfo-table.tsv", col_names = TRUE)
Domain architecture
The goal is to produce a cartoon-like plot for each homolog outlining their main features, such as the locations of the PFam domains (mainly the Hyp_reg_CWP), locations of the signal peptide and GPI-anchor, distribution of TANGO sequences. Note that all these features can be represented as a range with associated metadata. So the first step is to collect the coordinates of the features
# GPI-anchor
# use pred.gpi
# Pfam domains
pfam <- read_tsv("output/seq-feature/cauris-renamed-hmmer-scan.txt", col_types = "ciiiicciiidddiic")
# save feature file for Jalview examination
# pfam %>% filter(grepl("XP_028889033",seq_id)) %>% select(hmm_name, seq_id, envelope_start, envelope_end) %>% mutate(featuretype = "domain") %>% write_tsv("XP_028889033_features.jalview")
# I manually edited the feature file, so I commented out the line above to avoid accidentally
# overwriting my own edits
# feature set
# structure: id feature start end
feature <- bind_rows(
seqInfo %>% mutate(type = "entire protein", start = 1) %>% select(id = name, type, start, end = length),
pfam %>% select(id = seq_id, type = hmm_name, start = envelope_start, end = envelope_end),
# extend the signal peptide segment by 10 amino acids to make it more visible
signalp5 %>% mutate(type = "SignalP", end = end + 10) %>% select(id, type, start = start, end),
# extend the GPI-anchor C-terminus segment by 20 amino acids to make it more visible
pred.gpi %>% filter(is.gpi) %>% mutate(type = "GPI-anchor", start = cleavePos-10) %>%
select(id = name, type, start, end = length)
)
feature$type = ordered(feature$type, levels = c("entire protein", "Hyphal_reg_CWP", "Asp", "Hyr1", "SignalP", "GPI-anchor"))
feature.colors <- c("grey", "#1f78b4", "#b2df8a", "#ff7f00", "#e31a1c", "#6a3d9a")
# in order to plot properties of the sequences in an order that is consistent with the sequences' position in the gene tree
genetreeOrder <- scan("output/seq-feature/cauris-reorder-by-gene-tree.txt", what = "character")
Read 55 items
genetreeColor <- tibble(name = genetreeOrder) %>%
mutate(color = case_when(
grepl("haemuloni", name) ~ "#2596be70",
grepl("6684", name) ~ "#0e8c07",
grepl("B8441", name) ~ "#0e8c07",
grepl("B11220", name) ~ "#780a76",
grepl("B11221", name) ~ "#0409fb",
grepl("B11243", name) ~ "#ff4c00",
TRUE ~ "#000000"
))
feature$id <- ordered(feature$id, levels = rev(genetreeOrder))
write_tsv(feature, file = "output/seq-feature/R-feature-table.tsv", col_names = TRUE)
p <- ggplot(feature, aes(x = id, y = start)) +
geom_segment(aes(xend = id, yend = end, color = type), size = 2)
p + coord_flip() + theme_classic() + scale_color_manual(values = feature.colors) +
theme(axis.text.y = element_text(size = 6, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = c(0.8,0.8),
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(1, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Domain / Feature") +
ggtitle("Domain architecture")

ggsave("output/figure/20210425-homologs-domains-schematics.png", bg = "transparent", width = 7, height = 6)
TANGO prediction of \(\beta\)-aggregation prone sequences
The amyloid-like \(\beta\)-aggregation prone sequences have the ability to mediate self-aggregation, which boosts the local concentration of the adhesin molecules on the cell-surface. Similar to the S/T frequency above, we would like to use the output from the prediction algorithm, TANGO, to visulize the distribution of such sequence motifs along the length of the XP_028889033 homolog sequences.
Parse tango output
extract_tango <- function(tango_output, agg_threshold = 5, required_in_serial = 5) {
require(tidyverse)
tmp <- read_tsv(file = tango_output, col_types = "icddddd") %>%
# a boolean vector for residues above threshold
mutate(pass = Aggregation > agg_threshold)
pass.rle <- rle(tmp$pass) # this creates a run length encoding that will be useful for identifying the sub-sequences in a run longer than certain length
# --- Explanation ---
# this rle object is at the core of this function
# an example of the rle looks like
# lengths: int[1:10] 5 19 20 8 1 5 19 6 181 18
# values: logi[1:10] F T F T F T F T F T
# note that by definition the values will always be T/F interdigitated
# our goal is to identify the sub-sequences that is defined as a stretch of
# n consecutive positions with a score greater than the cutoff and record the
# sub-sequence, its length, start and end position, 90% quantile of the score
# --- End of explanation ---
# 1. assigns a unique id for each run of events
tmp$group <- rep(1:length(pass.rle$lengths), times = pass.rle$lengths)
# 2. extract the subsequences
agg.seq <- tmp %>%
filter(pass) %>% # drop residues not predicted to have aggregation potential
group_by(group) %>% # cluster by the runs
summarize(seq = paste0(aa, collapse = ""),
start = min(res), end = max(res), length = n(),
median = median(Aggregation),
q90 = quantile(Aggregation, probs = 0.9),
ivt = sum(aa %in% c("I","V","T")) / length(aa),
.groups = "drop") %>%
mutate(interval = start - lag(end) - 1) %>%
filter(length >= required_in_serial) %>%
select(-group)
return(agg.seq)
}
tango.output.files <- list.files(path = "output/tango", pattern = ".txt|.txt.gz", full.names = T)
# the read_csv() function used in the custom function can automatically decompress gzipped files
tango.res <- lapply(tango.output.files, extract_tango)
names(tango.res) <- gsub(".txt|.txt.gz", "", basename(tango.output.files))
# to add species information
tango.res.df <- bind_rows(tango.res, .id = "id") %>%
mutate(id = gsub("_B[0-9]+$", "", id))
# save the tango output
write_tsv(tango.res.df, "output/tango/tango_summary_table.tsv.gz")
# mutate(species = str_split(id, "_(?!.*_)", simplify = TRUE)[,2])
# extract the species names
# credit: https://stackoverflow.com/questions/20454768/how-to-split-a-string-from-right-to-left-like-pythons-rsplit
# the split pattern is equivalent to the rsplit() function in python
Plotting TANGO hits
# add species and strain information for plotting
tango <- left_join(select(seqInfo, name, id, species_id, strain), tango.res.df, by = c("id" = "id"))
# reorder the sequences for plotting
tango$name <- ordered(tango$name, levels = rev(genetreeOrder))
# plot
p1 <- ggplot(filter(feature, type == "entire protein"), aes(x = id, y = start)) +
geom_segment(aes(xend = id, yend = end), size = 2, color = "grey40")
p2 <- geom_segment(data = tango, aes(x = name, xend = name, y = ifelse(start-4 >= 0, start-4, 0), yend = end + 4, color = median), size = 2)
p3 <- geom_segment(data = filter(feature, type == "Hyphal_reg_CWP"), aes(x = id, y = start, xend = id, yend = end), size = 2, color = "#1f78b4")
p1 + p2 + p3 + coord_flip() + theme_classic() +
scale_color_distiller(type = "seq", palette = 17, direction = 1) +
theme(axis.text.y = element_text(size = 6, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = c(0.8,0.8),
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Median TANGO score") +
ggtitle("TANGO hits with Hyphal_reg_CWP domain masked")

ggsave("output/figure/20210425-tango-score-segment.png", width = 7, height = 6)
Tandem repeat structures
The non-NTD portion of the proteins evolve rapidly and many of them contain tandem repeats. Therefore, characterizing and visualizing the type, number and spatial distribution of the tandem repeats serve to highlight the differences in the non-NTD part of the proteins in this family.
To identify and group tandem repeats, I used XSTREAM with the following parameters java -Xmx1000m -Xms1000m -jar ~/sw/XSTREAM/xstream.jar $in -i.7 -I.7 -g3 -e2 -L15 -z -G -O. The parameters were chosen to identify degenerate tandem repeats that occur at least two times and must be a minimum length of 5 a.a. or longer and the minimum length of a tandem repeat domain (=period x copy #) must be greater than 15 a.a. Please see script/xstream.sh for explanation of the parameters.
tandem <- read_tsv("output/tandem-repeats/XSTREAM_cauris_outgr_i0.7_g3_m5_L15_chart.tsv",
col_types = "ciiifidcccd") %>%
rename(name = identifier) %>%
mutate(name = ordered(name, levels = rev(genetreeOrder)))
# now let's create a tibble for plotting, which would contain each instance of the tandem repeat on a separate row
tandem.div <- tandem %>%
rowwise(name) %>%
summarize(div = list(c(seq(from = start, to = end, by = period), end)), .groups = "drop") %>%
unnest(div)
# plot
require(RColorBrewer)
n.col = nlevels(tandem$type)
tr.col <- colorRampPalette(brewer.pal(12, "Paired")[3:12])(n.col)
p1 <- ggplot(filter(feature, type == "entire protein"), aes(x = id, y = start)) +
geom_segment(aes(xend = id, yend = end), size = 2.5, color = "grey40")
p2 <- geom_segment(data = tandem, aes(x = name, xend = name, y = start, yend = end, color = type, text = consensus_nogap), size = 2.5, alpha = 0.9)
p3 <- geom_segment(data = tandem.div, aes(x = name, xend = name, y = div, yend = div + 2), size = 2.5)
p4 <- geom_segment(data = filter(feature, type == "Hyphal_reg_CWP"), aes(x = id, y = start, xend = id, yend = end), color = "#1f78b4", size = 2.5)
p <- p1 + p2 + p3 + p4 + coord_flip() + theme_classic() +
scale_color_manual(values = tr.col) +
theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = "none",
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Median TANGO score") +
ggtitle("Tandem repeat domains with Hyphal_reg_CWP domain shown")
p

ggsave("output/figure/20210506-tandem-repeats.png", width = 7, height = 6)
Note Blue boxes indicate the PF11765 domains while all other non-grey boxes indicate XSTREAM-determined tandem repeat domains. Colors are used to group highly similar tandem repeats. The black thin lines demarcate adjacent tandem repeat units. The table below shows the copy number, period and consensus sequence for each tandem domain organized by the host sequences.
DT::datatable(
tandem %>%
rename(seqL = seqLength, err = consensus_error, seq = consensus_nogap) %>%
select(-seqAlign, -type, -consensus_gap, -seq, seq) %>%
arrange(desc(name)),
fillContainer = FALSE, options = list(pageLength = 10)
)
# combine sequence features with tandem repeats
tr.feature <- rbind(
feature %>%
filter(type %in% c("entire protein", "Hyphal_reg_CWP"), ) %>%
mutate(name = id, tip = ifelse(type == "entire protein", as.character(name), "PF11765")) %>%
select(name, type, start, end, tip),
tandem %>% mutate(type = paste0("tandem", type)) %>% select(name, type, start, end, tip = consensus_nogap)
) %>% mutate(type = droplevels(type))
# plot
require(RColorBrewer)
require(plotly)
n.col = nlevels(tr.feature$type)
tr.col <- c("grey40", "#1f78b4", colorRampPalette(brewer.pal(12, "Paired")[3:12])(n.col-2))
p1 <- ggplot(tr.feature, aes(x = name, y = start, xend = name, yend = end, color = type, text = tip)) +
geom_segment(size = 2)
p2 <- geom_segment(size = 2, alpha = 0.9)
p <- p1 + p2 + coord_flip() + theme_classic() +
scale_color_manual(values = tr.col) +
theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = "none",
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Median TANGO score") +
ggtitle("Tandem repeat domains with Hyphal_reg_CWP domain shown")
ggplotly(p, tooltip = "text")
LS0tCnRpdGxlOiAiQW5hbHl6ZSBYUF8wMjg4ODkwMzMgaG9tb2xvZ3MgaW4gQy4gYXVyaXMgc3RyYWlucyIKYXV0aG9yOiAiQmluIEhlIgpkYXRlOiAiMDQvMjMvMjAyMSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKYGBge3IgbG9hZF9saWJyYXJpZXMsIGVjaG8gPSBGQUxTRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkodGlkeXZlcnNlKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoY293cGxvdCkpCmBgYAoKIyMgR29hbAoKQW5hbHl6ZSB0aGUgZXZvbHV0aW9uIG9mIHNlcXVlbmNlIGZlYXR1cmVzIG9mIHRoZSBYUF8wMjg4ODkwMzMgaG9tb2xvZ3Mgd2l0aGluIF9DLiBhdXJpc18gc3BlY2llcy4gSW4gcGFydGljdWxhciwgd2UgYXJlIGludGVyZXN0ZWQgaW4gaW50cmEtc3BlY2llcyB2YXJpYXRpb24gaW4gY29weSBudW1iZXIsIE5URCBwcm90ZWluIHNlcXVlbmNlIGV2b2x1dGlvbmFyeSByYXRlcywgc3RhbGsgcmVwZWF0IG51bWJlcnMgYW5kIHNlcXVlbmNlcy4KCiMjIEhvbW9sb2dzIGlkZW50aWZpY2F0aW9uCkhvbW9sb2dzIG9mIHRoZSBQRjExNzY1IGRvbWFpbiBjb250YWluaW5nIHByb3RlaW5zIHdlcmUgaWRlbnRpZmllZCBpbiB0aGUgZml2ZSBzdHJhaW5zIG9mIF9DLiBhdXJpc18gdXNlZCBpbiBNdcOxb3ogX2V0IGFsLl8gMjAxOCBOYXQuIEdlbmV0LiBIb21vbG9ncyBmcm9tIF9DLiBwc2V1ZG9oYWVtdWxvbmlzXyBhbmQgX0MuIGhhZW11bG9uaV8gd2VyZSBhZGRlZCB0byBoZWxwIHByb3ZpZGUgdGhlIGV2b2x1dGlvbmFyeSBjb250ZXh0LCBlLmcuIHRpbWluZyBvZiBnZW5lIGR1cGxpY2F0aW9uIGFuZCBzZXF1ZW5jZSBldm9sdXRpb24gYm90aCB3aXRoaW4gYW5kIGJldHdlZW4gY2xvc2VseSByZWxhdGVkIHNwZWNpZXMuIEZpbmFsbHksIHR3byBob21vbG9ncyBmcm9tIHRoZSBvdXRyZ3JvdXAgc3BlY2llcyBfRC4gaGFuc2VuaWlfIHdlcmUgYWRkZWQgdG8gcm9vdCB0aGUgZ2VuZSB0cmVlLiBBIHRoaXJkIF9ELiBoYW5zZW5paV8gc2VxdWVuY2luZyB3aXRoIHRoZSBQRjExNzY1IGRvbWFpbiB3YXMgbm90IGluY2x1ZGVkIGFzIGl0IGJlbG9uZyB0byB0aGUgQ2xhdmlzcG9yYS9DYW5kaWRhIGR1cGxpY2F0ZSAyIGJyYW5jaCwgd2hpY2ggZGlkbid0IGluY2x1ZGUgYW55IF9DLiBhdXJpc18gc2VxdWVuY2VzLgoKIyMgRXZvbHV0aW9uIChkdXBsaWNhdGlvbnMgYW5kIGxvc3NlcykKIyMjIEdlbmUgdHJlZQpUaGUgZ2VuZSB0cmVlIGluZmVycmVkIGJhc2VkIG9uIHRoZSBQRjExNzY1IGRvbWFpbiBpbiBlYWNoIHNlcXVlbmNlIGlzIHByZXNlbnRlZCBiZWxvdzoKCiFbZ2VuZSB0cmVlXShvdXRwdXQvZ2VuZS10cmVlL3dpdGgtb3V0Z3JvdXAvUkF4TUxfYmlwYXJ0aXRpb25zLmNsdXN0YWxvXzQ5MjE4NjIucG5nKQoqKkZpZ3VyZSAxLiBSQXhNTCBpbmZlcnJlZCBnZW5lIHRyZWUgZm9yIEh5ci9JZmYtTGlrZSAoSElMKSBmYW1pbHkgbWVtYmVycyBpbiBfQy4gYXVyaXNfLCB0d28gTURSIGNsYWRlIHNwZWNpZXMgX0MuIHBzZXVkb2hhZW11bG9uaXNfIGFuZCBfQy4gaGFlbXVsb25pXywgYXMgd2VsbCBhcyBhbiBvdXRncm91cCBfRC4gaGFuc2VuaWlfLioqIFRoZSBicmFuY2ggdGhpY2tuZXNzIGlzIHNob3duIHByb3BvcnRpb25hbCB0byB0aGUgdmFsdWUgb2YgdGhlIHJhcGlkIGJvb3RzdHJhcHBpbmcgdmFsdWUuIFRoZSB0cmVlIGlzIG1hbnVhbGx5IHJvb3RlZCBvbiB0aGUgdHdvIF9ELiBoYW5zZW5paV8gc2VxdWVuY2VzLiBUaGUgcm9vdCBjaG9pY2UgaXMgYmFzZWQgb24gdGhlIGdlbmUgdHJlZSBpbmNsdWRpbmcgaG9tb2xvZ3MgZnJvbSBhY3Jvc3MgdGhlIEFzY29teWNldGVzLiBUaGUgc2hvcnQgdGVybWluYWwgYnJhbmNoIGxlbmd0aHMgYW1vbmcgdGhlIF9DLiBhdXJpc18gc3RyYWlucyBpbmRpY2F0ZSB0aGF0IHRoZXJlIGhhZCBiZWVuIGxpdHRsZSBkaXZlcmdlbmNlIGluIHRoZSBQRjExNzY1IGRvbWFpbiBpbiB0aGVzZSBzZXF1ZW5jZXMuIExhc3RseSwgdGhlIGNvbG9ycyBvZiB0aGUgbGVhZiBub2RlIG5hbWVzIGZvciB0aGUgX0MuIGF1cmlzXyBzdHJhaW5zIGFyZSBiYXNlZCBvbiBNdcOxb3ogX2V0IGFsLl8gMjAxOCBOYXQuIEdlbmV0LgoKIyMjIFJlY29uY2lsaWF0aW9uIGFuZCByZWFycmFuZ2VtZW50ClRvIGluZmVyIHRoZSB0aW1pbmcgb2YgZ2VuZSBkdXBsaWNhdGlvbiBhbmQgbG9zcyBldmVudHMsIHRoZSBnZW5lIHRyZWUgaXMgcmVjb25jaWxlZCB3aXRoIHRoZSBzcGVjaWVzIHRyZWUgaW4gTm90dW5nIDIuOS4gUmVhcnJhbmdlbWVudCBvZiB0aGUgcmVjb25jaWxlZCBnZW5lIHRyZWUgd2FzIHBlcmZvcm1lZCBpbiB0aGUgc2FtZSBzb2Z0d2FyZSwgYWxsb3dpbmcgZm9yIHN3YXBwaW5nIG9mIGJyYW5jaGVzIHdpdGggcmFwaWQgYm9vdHN0cmFwcGluZyB2YWx1ZXMgbG93ZXIgdGhhbiAqKjkwJSoqLiBUaGUgcmVhcnJhbmdlZCB0cmVlIGhhcyBhIHRvdGFsIG9mICoqMTUqKiBkdXBsaWNhdGlvbiBhbmQgKioxMyoqIGxvc3Nlcy4gTm90ZSB0aGF0IHRoZSBjbGFkZSBJIHN0cmFpbiA2Njg0IGFwcGVhcmVkIHRvIGhhdmUgZXhwZXJpZW5jZWQgc2V2ZXJhbCBsb3NzZXMsIGJ1dCB0aGlzIGlzIHZlcnkgbGlrZWx5IGR1ZSB0byB0aGUgcmVsYXRpdmVseSBwb29yIGFzc2VtYmx5IHN0YXR1cyBvZiB0aGUgc3RyYWluLCBub3QgcmVhbCBldm9sdXRpb25hcnkgbG9zc2VzLgoKIyMgRXZvbHV0aW9uIG9mIHNlcXVlbmNlIGZlYXR1cmVzCiMjIyBCdWlsZCBkYXRhc2V0cwoxLiBTZXF1ZW5jZSBJRHMsIHNwZWNpZXMgYW5kIHN0cmFpbiBpbmZvcm1hdGlvbi4KMS4gQWRoZXNpbiBwcmVkaWN0aW9uIHJlc3VsdHMKCiAgICBGdW5nYWxSViB0aHJlc2hvbGQ6IDAuNTE7IEZhYVByZWQgdXNpbmcgQUNITSBtb2RlbCB3aXRoIHRoZSByZWNvbW1lbmRlZCAtMC44IHRocmVzaG9sZC4KICAgIAoxLiBHUEktYW5jaG9yIHByZWRpY3Rpb24gKGluY2x1ZGluZyBzaWduYWwgcGVwdGlkZSkKCiAgICBHUEktYW5jaG9yZWQgcHJvdGVpbnMgYXJlIGNoYXJhY3Rlcml6ZWQgYnkgYW4gTi10ZXJtaW5hbCBzaWduYWwgcGVwdGlkZSwgd2hpY2ggd291bGQgZGlyZWN0IHRoZSBwcm90ZWluIHRvIHRoZSBzZWNyZXRhcnkgcGF0aHdheSwgYW5kIGEgQy10ZXJtaW5hbCBHUEktYW5jaG9yIHBlcHRpZGUsIHdoaWNoIHdvdWxkIGJlIGNsZWF2ZWQgYW5kIHJlcGxhY2VkIGJ5IHRoZSBHUEktYW5jaG9yLCBhbGxvd2luZyB0aGUgcHJvdGVpbiB0byBiZSB0ZXRoZXJlZCB0byB0aGUgY2VsbCB3YWxsLiBGb3Igc2lnbmFsIHBlcHRpZGUsIEkgdXNlZCBTaWduYWxQIHNlcnZlci4gSXRzIGxhdGVzdCB2ZXJzaW9uIGlzIDUuMC4gQnV0IEkgYWxzbyByYW4gdGhlIHNlcXVlbmNlcyB0aHJvdWdoIHRoZWlyIDQuMSB2ZXJzaW9uLCB3aXRoIHR3byBzZXR0aW5ncy4gVGhlIHJlc3VsdHMgb2YgdGhlIGxhdHRlciB0d28gYXJlIGFsbW9zdCBpZGVudGljYWwsIGV4Y2VwdCBmb3Igb25lIHNlcXVlbmNlICJYUF8wMjQ3MTEzNTAuMSIsIHdoaWNoIGlzIG9ubHkgaW5jbHVkZWQgaW4gdGhlIHNlbnNpdGl2ZSB2ZXJzaW9uLCBhbmQgaGFzIGEgcHJvYmFiaWxpdHkgbG93ZXIgdGhhbiAwLjUuCiAgICBGb3IgR1BJLWFuY2hvciBwcmVkaWN0aW9uLCBJIHVzZWQgdGhlIFtQcmVkR1BJIHNlcnZlcl0oaHR0cDovL2dwY3IuYmlvY29tcC51bmliby5pdC9wcmVkZ3BpLykuCiAgICBGb3Igc2lnbmFsIHBlcHRpZGUgcHJlZGljdGlvbiwgSSB1c2VkIHRoZSBbU2lnbmFsUCA1LjAgc2VydmVyXShodHRwOi8vd3d3LmNicy5kdHUuZGsvc2VydmljZXMvU2lnbmFsUC8pCgpgYGB7ciBsb2FkX3NlcV9pbmZvfQpzcHMubGlzdCA8LSBjKCJDYXVyaXMiLCJDcHNldWRvaGFlbXVsb25pcyIsIkNoYWVtdWxvbmkiLCJEaGFuc2VuaWkiKQpzZXFJbmZvIDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtc2VxaW5mby50c3YiLCBjb21tZW50ID0gIiMiLCBjb2xfdHlwZXMgPSAiY2NjY2kiKSAlPiUgCiAgbXV0YXRlKHNwZWNpZXNfaWQgPSBmYWN0b3Ioc3BlY2llcywgbGV2ZWxzID0gc3BzLmxpc3QpLCBzcGVjaWVzID0gTlVMTCkKYGBgCgojIyMgQWRoZXNpbiBwcmVkaWN0aW9uCmBgYHtyIGFkaGVzaW5fcHJlZGljdGlvbn0KZnJ2LnRoID0gMC41MTEgIyByZWNvbW1lbmRlZCBGdW5nYWxSViBzY29yZSB0aHJlc2hvbGQKZnJ2IDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtZnVuZ2FscnYudHh0Iiwgc2tpcCA9IDMsIGNvbF9uYW1lcyA9IGMoIm5hbWUiLCJmcnYuc2NvcmUiKSwgY29sX3R5cGVzID0gImNkIikgJT4lIAogIG11dGF0ZShuYW1lID0gc3RyX3N1YihuYW1lLCAyKSwgZnJ2LnByZWQgPSBmcnYuc2NvcmUgPiBmcnYudGgpCmZhYSA8LSByZWFkX3Rzdigib3V0cHV0L3NlcS1mZWF0dXJlL2NhdXJpcy1yZW5hbWVkLWZhYXByZWQudHh0IiwgY29sX25hbWVzID0gYygibmFtZSIsImZhYS5zY29yZSIsImZhYS5wcmVkIiksIGNvbF90eXBlcyA9ICJjZGMiKSAlPiUgCiAgbXV0YXRlKGZhYS5wcmVkID0gaWZlbHNlKGZhYS5wcmVkID09ICJBZGhlc2luIiwgVFJVRSwgRkFMU0UpKQppZigiZnJ2LnNjb3JlIiAlaW4lIG5hbWVzKHNlcUluZm8pKQogIHNlcUluZm8gPC0gc2VsZWN0KHNlcUluZm8sIC1mcnYuc2NvcmUsIC1mcnYucHJlZCwgLWZhYS5zY29yZSwgLWZhYS5wcmVkKQpzZXFJbmZvIDwtIHNlcUluZm8gJT4lIGxlZnRfam9pbihmcnYpICU+JSBsZWZ0X2pvaW4oZmFhKQpzZXFJbmZvICU+JSAKICBncm91cF9ieShzcGVjaWVzX2lkLCBzdHJhaW4pICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgZnVuZ2FsUlYgPSBzdW0oZnJ2LnNjb3JlID4gMC41MTEpLCBmYWFwcmVkID0gc3VtKGZhYS5wcmVkLCBuYS5ybSA9IFQpLCAKICAgICAgICAgICAgYm90aCA9IHN1bShmcnYuc2NvcmUgPiAwLjUxMSAmIGZhYS5wcmVkKSkKYGBgCiMjIyBTaWduYWxQIGFuZCBHUEkgcHJlZGljdGlvbgpgYGB7ciBzaWduYWxQLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQojIFNpZ25hbCBwZXB0aWRlCmdmZi5uYW1lcyA8LSBjKCJpZCIsICJzb3VyY2UiLCAibmFtZSIsICJzdGFydCIsICJlbmQiLCAicHJvYiIsICJuYTEiLCAibmEyIiwgIm5hMyIpCnNpZ25hbHA1IDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtc2lnbmFscDUuZ2ZmMyIsIGNvbW1lbnQgPSAiIyIsIGNvbF9uYW1lcyA9IGdmZi5uYW1lcywgY29sX3R5cGVzID0gImNjY2lpZGNjYyIpCgppZigic2lnbmFscCIgJWluJSBuYW1lcyhzZXFJbmZvKSkKICBzZXFJbmZvIDwtIHNlbGVjdChzZXFJbmZvLCAtc2lnbmFscCkKCnNlcUluZm8gPC0gbGVmdF9qb2luKHNlcUluZm8sIHNlbGVjdChzaWduYWxwNSwgbmFtZSA9IGlkLCBwcm9iKSwgYnkgPSBjKCJuYW1lIiA9ICJuYW1lIikpICU+JSAKICBtdXRhdGUoc2lnbmFscCA9ICFpcy5uYShwcm9iKSkgJT4lIHNlbGVjdCgtcHJvYikKYGBgCgpgYGB7ciBncGl9CnRtcCA8LSByZWFkX2RlbGltKCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtcHJlZGdwaS50eHQiLCBkZWxpbSA9ICJ8IiwgY29sX25hbWVzID0gYygibmFtZSIsImZwIiwib21lZ2EiKSkKcHJlZC5ncGkgPC0gdG1wICU+JSAgCiAgbXV0YXRlKG5hbWUgPSBzdHJfc3ViKG5hbWUsIDIsIC0yKSwgIyByZW1vdmUgPiBhbmQgdGhlIHRyYWlsaW5nIHNwYWNlCiAgICAgICAgIGZwID0gYXMubnVtZXJpYyhzdHJfc3ViKGZwLCA5LCAtMikpLCAjIGV4dHJhY3QgdGhlIG51bWVyaWMgcGFydAogICAgICAgICBpcy5ncGkgPSBmcCA8PSAwLjAxLCAgICAjIGJhc2VkIG9uIHRoZSBjdXRvZmYgb2YgdGhlIFByZWRHUEkgc2VydmVyIChwcm9iIDwgOTklIC0+IG5vdCBHUEktYW5jaG9yZWQpCiAgICAgICAgIG9tZWdhID0gc3RyX3N1YihvbWVnYSwgOCksCiAgICAgICAgIGNsZWF2ZVJlcyA9IHN0cl9zdWIob21lZ2EsIDEsIDEpLAogICAgICAgICBjbGVhdmVQb3MgPSBhcy5pbnRlZ2VyKHN0cl9zdWIob21lZ2EsIDMpKSwKICAgICAgICAgKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzZXFJbmZvLCBuYW1lLCBsZW5ndGgpLCBieSA9IGMoIm5hbWUiID0gIm5hbWUiKSkKCiMgcmVtb3ZlIHRoZSBjb2x1bW4gaWYgaXQgYWxyZWFkeSBleGlzdHMKaWYoInByZWQuZ3BpIiAlaW4lIG5hbWVzKHNlcUluZm8pKQogIHNlcUluZm8gPC0gc2VsZWN0KHNlcUluZm8sIC1wcmVkLmdwaSkKc2VxSW5mbyA8LSBsZWZ0X2pvaW4oc2VxSW5mbywgc2VsZWN0KHByZWQuZ3BpLCBuYW1lLCBwcmVkLmdwaSA9IGlzLmdwaSksIGJ5ID0gYygibmFtZSI9Im5hbWUiKSkKCnNlcUluZm8gJT4lIAogIGdyb3VwX2J5KHNwZWNpZXNfaWQsIHN0cmFpbikgJT4lIAogIHN1bW1hcml6ZShUb3RhbCA9IG4oKSwgU2lnbmFsUCA9IHN1bShzaWduYWxwKSwgR1BJX1ByZWQgPSBzdW0ocHJlZC5ncGkpLCBCb3RoID0gc3VtKHNpZ25hbHAgJiBwcmVkLmdwaSkpCgp3cml0ZV90c3Yoc2VxSW5mbywgIm91dHB1dC9zZXEtZmVhdHVyZS9SLXNlcWluZm8tdGFibGUudHN2IiwgY29sX25hbWVzID0gVFJVRSkKYGBgCgojIyMgRG9tYWluIGFyY2hpdGVjdHVyZQoKVGhlIGdvYWwgaXMgdG8gcHJvZHVjZSBhIGNhcnRvb24tbGlrZSBwbG90IGZvciBlYWNoIGhvbW9sb2cgb3V0bGluaW5nIHRoZWlyIG1haW4gZmVhdHVyZXMsIHN1Y2ggYXMgdGhlIGxvY2F0aW9ucyBvZiB0aGUgUEZhbSBkb21haW5zIChtYWlubHkgdGhlIEh5cF9yZWdfQ1dQKSwgbG9jYXRpb25zIG9mIHRoZSBzaWduYWwgcGVwdGlkZSBhbmQgR1BJLWFuY2hvciwgZGlzdHJpYnV0aW9uIG9mIFRBTkdPIHNlcXVlbmNlcy4gTm90ZSB0aGF0IGFsbCB0aGVzZSBmZWF0dXJlcyBjYW4gYmUgcmVwcmVzZW50ZWQgYXMgYSByYW5nZSB3aXRoIGFzc29jaWF0ZWQgbWV0YWRhdGEuIFNvIHRoZSBmaXJzdCBzdGVwIGlzIHRvIGNvbGxlY3QgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBmZWF0dXJlcwoKYGBge3J9CiMgR1BJLWFuY2hvcgojIHVzZSBwcmVkLmdwaQojIFBmYW0gZG9tYWlucwpwZmFtIDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtaG1tZXItc2Nhbi50eHQiLCBjb2xfdHlwZXMgPSAiY2lpaWljY2lpaWRkZGlpYyIpCiMgc2F2ZSBmZWF0dXJlIGZpbGUgZm9yIEphbHZpZXcgZXhhbWluYXRpb24KIyBwZmFtICU+JSBmaWx0ZXIoZ3JlcGwoIlhQXzAyODg4OTAzMyIsc2VxX2lkKSkgJT4lIHNlbGVjdChobW1fbmFtZSwgc2VxX2lkLCBlbnZlbG9wZV9zdGFydCwgZW52ZWxvcGVfZW5kKSAlPiUgbXV0YXRlKGZlYXR1cmV0eXBlID0gImRvbWFpbiIpICU+JSB3cml0ZV90c3YoIlhQXzAyODg4OTAzM19mZWF0dXJlcy5qYWx2aWV3IikKIyBJIG1hbnVhbGx5IGVkaXRlZCB0aGUgZmVhdHVyZSBmaWxlLCBzbyBJIGNvbW1lbnRlZCBvdXQgdGhlIGxpbmUgYWJvdmUgdG8gYXZvaWQgYWNjaWRlbnRhbGx5IAojIG92ZXJ3cml0aW5nIG15IG93biBlZGl0cwoKIyBmZWF0dXJlIHNldAojIHN0cnVjdHVyZTogaWQgIGZlYXR1cmUgIHN0YXJ0ICBlbmQKZmVhdHVyZSA8LSBiaW5kX3Jvd3MoCiAgc2VxSW5mbyAlPiUgbXV0YXRlKHR5cGUgPSAiZW50aXJlIHByb3RlaW4iLCBzdGFydCA9IDEpICU+JSBzZWxlY3QoaWQgPSBuYW1lLCB0eXBlLCBzdGFydCwgZW5kID0gbGVuZ3RoKSwKICBwZmFtICU+JSBzZWxlY3QoaWQgPSBzZXFfaWQsIHR5cGUgPSBobW1fbmFtZSwgc3RhcnQgPSBlbnZlbG9wZV9zdGFydCwgZW5kID0gZW52ZWxvcGVfZW5kKSwKICAjIGV4dGVuZCB0aGUgc2lnbmFsIHBlcHRpZGUgc2VnbWVudCBieSAxMCBhbWlubyBhY2lkcyB0byBtYWtlIGl0IG1vcmUgdmlzaWJsZQogIHNpZ25hbHA1ICU+JSBtdXRhdGUodHlwZSA9ICJTaWduYWxQIiwgZW5kID0gZW5kICsgMTApICU+JSBzZWxlY3QoaWQsIHR5cGUsIHN0YXJ0ID0gc3RhcnQsIGVuZCksCiAgIyBleHRlbmQgdGhlIEdQSS1hbmNob3IgQy10ZXJtaW51cyBzZWdtZW50IGJ5IDIwIGFtaW5vIGFjaWRzIHRvIG1ha2UgaXQgbW9yZSB2aXNpYmxlCiAgcHJlZC5ncGkgJT4lIGZpbHRlcihpcy5ncGkpICU+JSBtdXRhdGUodHlwZSA9ICJHUEktYW5jaG9yIiwgc3RhcnQgPSBjbGVhdmVQb3MtMTApICU+JSAKICAgIHNlbGVjdChpZCA9IG5hbWUsIHR5cGUsIHN0YXJ0LCBlbmQgPSBsZW5ndGgpCikKZmVhdHVyZSR0eXBlID0gb3JkZXJlZChmZWF0dXJlJHR5cGUsIGxldmVscyA9IGMoImVudGlyZSBwcm90ZWluIiwgIkh5cGhhbF9yZWdfQ1dQIiwgIkFzcCIsICJIeXIxIiwgIlNpZ25hbFAiLCAiR1BJLWFuY2hvciIpKQpmZWF0dXJlLmNvbG9ycyA8LSBjKCJncmV5IiwgIiMxZjc4YjQiLCAiI2IyZGY4YSIsICIjZmY3ZjAwIiwgIiNlMzFhMWMiLCAiIzZhM2Q5YSIpCiMgaW4gb3JkZXIgdG8gcGxvdCBwcm9wZXJ0aWVzIG9mIHRoZSBzZXF1ZW5jZXMgaW4gYW4gb3JkZXIgdGhhdCBpcyBjb25zaXN0ZW50IHdpdGggdGhlIHNlcXVlbmNlcycgcG9zaXRpb24gaW4gdGhlIGdlbmUgdHJlZQpnZW5ldHJlZU9yZGVyIDwtIHNjYW4oIm91dHB1dC9zZXEtZmVhdHVyZS9jYXVyaXMtcmVvcmRlci1ieS1nZW5lLXRyZWUudHh0Iiwgd2hhdCA9ICJjaGFyYWN0ZXIiKQpnZW5ldHJlZUNvbG9yIDwtIHRpYmJsZShuYW1lID0gZ2VuZXRyZWVPcmRlcikgJT4lIAogIG11dGF0ZShjb2xvciA9IGNhc2Vfd2hlbigKICAgIGdyZXBsKCJoYWVtdWxvbmkiLCBuYW1lKSB+ICIjMjU5NmJlNzAiLAogICAgZ3JlcGwoIjY2ODQiLCBuYW1lKSB+ICIjMGU4YzA3IiwKICAgIGdyZXBsKCJCODQ0MSIsIG5hbWUpIH4gIiMwZThjMDciLAogICAgZ3JlcGwoIkIxMTIyMCIsIG5hbWUpIH4gIiM3ODBhNzYiLAogICAgZ3JlcGwoIkIxMTIyMSIsIG5hbWUpIH4gIiMwNDA5ZmIiLAogICAgZ3JlcGwoIkIxMTI0MyIsIG5hbWUpIH4gIiNmZjRjMDAiLAogICAgVFJVRSB+ICIjMDAwMDAwIgogICAgKSkKZmVhdHVyZSRpZCA8LSBvcmRlcmVkKGZlYXR1cmUkaWQsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkKd3JpdGVfdHN2KGZlYXR1cmUsIGZpbGUgPSAib3V0cHV0L3NlcS1mZWF0dXJlL1ItZmVhdHVyZS10YWJsZS50c3YiLCBjb2xfbmFtZXMgPSBUUlVFKQpgYGAKCmBgYHtyIHBsb3RfZmVhdHVyZXMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTksIHdhcm5pbmc9RkFMU0V9CnAgPC0gZ2dwbG90KGZlYXR1cmUsIGFlcyh4ID0gaWQsIHkgPSBzdGFydCkpICsgCiAgZ2VvbV9zZWdtZW50KGFlcyh4ZW5kID0gaWQsIHllbmQgPSBlbmQsIGNvbG9yID0gdHlwZSksIHNpemUgPSAyKQpwICsgY29vcmRfZmxpcCgpICsgdGhlbWVfY2xhc3NpYygpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGZlYXR1cmUuY29sb3JzKSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9IHJldihnZW5ldHJlZUNvbG9yJGNvbG9yKSksCiAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LDAuOCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYWxwaGEoImxpZ2h0Ymx1ZSIsMC41KSkpICsKICB5bGltKDEsIDQ1MDApICsgbGFicyh5ID0gIlBvc2l0aW9uIGluIHNlcXVlbmNlIiwgeCA9ICJTZXF1ZW5jZXMiLCBjb2xvciA9ICJEb21haW4gLyBGZWF0dXJlIikgKyAKICBnZ3RpdGxlKCJEb21haW4gYXJjaGl0ZWN0dXJlIikKZ2dzYXZlKCJvdXRwdXQvZmlndXJlLzIwMjEwNDI1LWhvbW9sb2dzLWRvbWFpbnMtc2NoZW1hdGljcy5wbmciLCBiZyA9ICJ0cmFuc3BhcmVudCIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNikKYGBgCgojIyMgVEFOR08gcHJlZGljdGlvbiBvZiAkXGJldGEkLWFnZ3JlZ2F0aW9uIHByb25lIHNlcXVlbmNlcwoKVGhlIGFteWxvaWQtbGlrZSAkXGJldGEkLWFnZ3JlZ2F0aW9uIHByb25lIHNlcXVlbmNlcyBoYXZlIHRoZSBhYmlsaXR5IHRvIG1lZGlhdGUgc2VsZi1hZ2dyZWdhdGlvbiwgd2hpY2ggYm9vc3RzIHRoZSBsb2NhbCBjb25jZW50cmF0aW9uIG9mIHRoZSBhZGhlc2luIG1vbGVjdWxlcyBvbiB0aGUgY2VsbC1zdXJmYWNlLiBTaW1pbGFyIHRvIHRoZSBTL1QgZnJlcXVlbmN5IGFib3ZlLCB3ZSB3b3VsZCBsaWtlIHRvIHVzZSB0aGUgb3V0cHV0IGZyb20gdGhlIHByZWRpY3Rpb24gYWxnb3JpdGhtLCBUQU5HTywgdG8gdmlzdWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBzdWNoIHNlcXVlbmNlIG1vdGlmcyBhbG9uZyB0aGUgbGVuZ3RoIG9mIHRoZSBYUF8wMjg4ODkwMzMgaG9tb2xvZyBzZXF1ZW5jZXMuCgojIyMjIFBhcnNlIHRhbmdvIG91dHB1dApgYGB7ciBleHRyYWN0X3RhbmdvX2luZm99CmV4dHJhY3RfdGFuZ28gPC0gZnVuY3Rpb24odGFuZ29fb3V0cHV0LCBhZ2dfdGhyZXNob2xkID0gNSwgcmVxdWlyZWRfaW5fc2VyaWFsID0gNSkgewogICAgcmVxdWlyZSh0aWR5dmVyc2UpCiAgICB0bXAgPC0gcmVhZF90c3YoZmlsZSA9IHRhbmdvX291dHB1dCwgY29sX3R5cGVzID0gImljZGRkZGQiKSAlPiUgCiAgICAgICAgIyBhIGJvb2xlYW4gdmVjdG9yIGZvciByZXNpZHVlcyBhYm92ZSB0aHJlc2hvbGQKICAgICAgICBtdXRhdGUocGFzcyA9IEFnZ3JlZ2F0aW9uID4gYWdnX3RocmVzaG9sZCkKICAgIHBhc3MucmxlIDwtIHJsZSh0bXAkcGFzcykgIyB0aGlzIGNyZWF0ZXMgYSBydW4gbGVuZ3RoIGVuY29kaW5nIHRoYXQgd2lsbCBiZSB1c2VmdWwgZm9yIGlkZW50aWZ5aW5nIHRoZSBzdWItc2VxdWVuY2VzIGluIGEgcnVuIGxvbmdlciB0aGFuIGNlcnRhaW4gbGVuZ3RoCiAgICAjIC0tLSBFeHBsYW5hdGlvbiAtLS0KICAgICMgdGhpcyBybGUgb2JqZWN0IGlzIGF0IHRoZSBjb3JlIG9mIHRoaXMgZnVuY3Rpb24KICAgICMgYW4gZXhhbXBsZSBvZiB0aGUgcmxlIGxvb2tzIGxpa2UKICAgICMgICBsZW5ndGhzOiBpbnRbMToxMF0gNSAxOSAyMCA4IDEgNSAxOSA2IDE4MSAxOAogICAgIyAgIHZhbHVlczogbG9naVsxOjEwXSBGIFQgIEYgIFQgRiBUIEYgIFQgRiAgIFQKICAgICMgICBub3RlIHRoYXQgYnkgZGVmaW5pdGlvbiB0aGUgdmFsdWVzIHdpbGwgYWx3YXlzIGJlIFQvRiBpbnRlcmRpZ2l0YXRlZAogICAgIyBvdXIgZ29hbCBpcyB0byBpZGVudGlmeSB0aGUgc3ViLXNlcXVlbmNlcyB0aGF0IGlzIGRlZmluZWQgYXMgYSBzdHJldGNoIG9mIAogICAgIyBuIGNvbnNlY3V0aXZlIHBvc2l0aW9ucyB3aXRoIGEgc2NvcmUgZ3JlYXRlciB0aGFuIHRoZSBjdXRvZmYgYW5kIHJlY29yZCB0aGUKICAgICMgc3ViLXNlcXVlbmNlLCBpdHMgbGVuZ3RoLCBzdGFydCBhbmQgZW5kIHBvc2l0aW9uLCA5MCUgcXVhbnRpbGUgb2YgdGhlIHNjb3JlCiAgICAjIC0tLSBFbmQgb2YgZXhwbGFuYXRpb24gLS0tCiAgICAjIDEuIGFzc2lnbnMgYSB1bmlxdWUgaWQgZm9yIGVhY2ggcnVuIG9mIGV2ZW50cwogICAgdG1wJGdyb3VwIDwtIHJlcCgxOmxlbmd0aChwYXNzLnJsZSRsZW5ndGhzKSwgdGltZXMgPSBwYXNzLnJsZSRsZW5ndGhzKQogICAgIyAyLiBleHRyYWN0IHRoZSBzdWJzZXF1ZW5jZXMKICAgIGFnZy5zZXEgPC0gdG1wICU+JSAKICAgICAgICBmaWx0ZXIocGFzcykgJT4lICMgZHJvcCByZXNpZHVlcyBub3QgcHJlZGljdGVkIHRvIGhhdmUgYWdncmVnYXRpb24gcG90ZW50aWFsCiAgICAgICAgZ3JvdXBfYnkoZ3JvdXApICU+JSAjIGNsdXN0ZXIgYnkgdGhlIHJ1bnMKICAgICAgICBzdW1tYXJpemUoc2VxID0gcGFzdGUwKGFhLCBjb2xsYXBzZSA9ICIiKSwKICAgICAgICAgICAgICAgICAgc3RhcnQgPSBtaW4ocmVzKSwgZW5kID0gbWF4KHJlcyksIGxlbmd0aCA9IG4oKSwKICAgICAgICAgICAgICAgICAgbWVkaWFuID0gbWVkaWFuKEFnZ3JlZ2F0aW9uKSwKICAgICAgICAgICAgICAgICAgcTkwID0gcXVhbnRpbGUoQWdncmVnYXRpb24sIHByb2JzID0gMC45KSwKICAgICAgICAgICAgICAgICAgaXZ0ID0gc3VtKGFhICVpbiUgYygiSSIsIlYiLCJUIikpIC8gbGVuZ3RoKGFhKSwKICAgICAgICAgICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogICAgICAgIG11dGF0ZShpbnRlcnZhbCA9IHN0YXJ0IC0gbGFnKGVuZCkgLSAxKSAlPiUgCiAgICAgICAgZmlsdGVyKGxlbmd0aCA+PSByZXF1aXJlZF9pbl9zZXJpYWwpICU+JSAKICAgICAgICBzZWxlY3QoLWdyb3VwKQogICAgcmV0dXJuKGFnZy5zZXEpCn0KYGBgCgpgYGB7ciBhcHBseX0KdGFuZ28ub3V0cHV0LmZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aCA9ICJvdXRwdXQvdGFuZ28iLCBwYXR0ZXJuID0gIi50eHR8LnR4dC5neiIsIGZ1bGwubmFtZXMgPSBUKQojIHRoZSByZWFkX2NzdigpIGZ1bmN0aW9uIHVzZWQgaW4gdGhlIGN1c3RvbSBmdW5jdGlvbiBjYW4gYXV0b21hdGljYWxseSBkZWNvbXByZXNzIGd6aXBwZWQgZmlsZXMKdGFuZ28ucmVzIDwtIGxhcHBseSh0YW5nby5vdXRwdXQuZmlsZXMsIGV4dHJhY3RfdGFuZ28pCm5hbWVzKHRhbmdvLnJlcykgPC0gZ3N1YigiLnR4dHwudHh0Lmd6IiwgIiIsIGJhc2VuYW1lKHRhbmdvLm91dHB1dC5maWxlcykpCiMgdG8gYWRkIHNwZWNpZXMgaW5mb3JtYXRpb24KdGFuZ28ucmVzLmRmIDwtIGJpbmRfcm93cyh0YW5nby5yZXMsIC5pZCA9ICJpZCIpICU+JQogIG11dGF0ZShpZCA9IGdzdWIoIl9CWzAtOV0rJCIsICIiLCBpZCkpCiMgc2F2ZSB0aGUgdGFuZ28gb3V0cHV0CndyaXRlX3Rzdih0YW5nby5yZXMuZGYsICJvdXRwdXQvdGFuZ28vdGFuZ29fc3VtbWFyeV90YWJsZS50c3YuZ3oiKQojIG11dGF0ZShzcGVjaWVzID0gc3RyX3NwbGl0KGlkLCAiXyg/IS4qXykiLCBzaW1wbGlmeSA9IFRSVUUpWywyXSkgCiMgZXh0cmFjdCB0aGUgc3BlY2llcyBuYW1lcwojIGNyZWRpdDogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjA0NTQ3NjgvaG93LXRvLXNwbGl0LWEtc3RyaW5nLWZyb20tcmlnaHQtdG8tbGVmdC1saWtlLXB5dGhvbnMtcnNwbGl0CiMgdGhlIHNwbGl0IHBhdHRlcm4gaXMgZXF1aXZhbGVudCB0byB0aGUgcnNwbGl0KCkgZnVuY3Rpb24gaW4gcHl0aG9uCmBgYAoKIyMjIyBQbG90dGluZyBUQU5HTyBoaXRzCmBgYHtyIHBsb3RfdGFuZ29fc2VxdWVuY2VzLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD05fQojIGFkZCBzcGVjaWVzIGFuZCBzdHJhaW4gaW5mb3JtYXRpb24gZm9yIHBsb3R0aW5nCnRhbmdvIDwtIGxlZnRfam9pbihzZWxlY3Qoc2VxSW5mbywgbmFtZSwgaWQsIHNwZWNpZXNfaWQsIHN0cmFpbiksICB0YW5nby5yZXMuZGYsIGJ5ID0gYygiaWQiID0gImlkIikpCiMgcmVvcmRlciB0aGUgc2VxdWVuY2VzIGZvciBwbG90dGluZwp0YW5nbyRuYW1lIDwtIG9yZGVyZWQodGFuZ28kbmFtZSwgbGV2ZWxzID0gcmV2KGdlbmV0cmVlT3JkZXIpKQojIHBsb3QKcDEgPC0gZ2dwbG90KGZpbHRlcihmZWF0dXJlLCB0eXBlID09ICJlbnRpcmUgcHJvdGVpbiIpLCBhZXMoeCA9IGlkLCB5ID0gc3RhcnQpKSArIAogIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IGlkLCB5ZW5kID0gZW5kKSwgc2l6ZSA9IDIsIGNvbG9yID0gImdyZXk0MCIpCnAyIDwtIGdlb21fc2VnbWVudChkYXRhID0gdGFuZ28sIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsICB5ID0gaWZlbHNlKHN0YXJ0LTQgPj0gMCwgc3RhcnQtNCwgMCksIHllbmQgPSBlbmQgKyA0LCBjb2xvciA9IG1lZGlhbiksIHNpemUgPSAyKQpwMyA8LSBnZW9tX3NlZ21lbnQoZGF0YSA9IGZpbHRlcihmZWF0dXJlLCB0eXBlID09ICJIeXBoYWxfcmVnX0NXUCIpLCBhZXMoeCA9IGlkLCB5ID0gc3RhcnQsIHhlbmQgPSBpZCwgeWVuZCA9IGVuZCksIHNpemUgPSAyLCBjb2xvciA9ICIjMWY3OGI0IikKcDEgKyBwMiArIHAzICsgY29vcmRfZmxpcCgpICsgdGhlbWVfY2xhc3NpYygpICsgCiAgc2NhbGVfY29sb3JfZGlzdGlsbGVyKHR5cGUgPSAic2VxIiwgcGFsZXR0ZSA9IDE3LCBkaXJlY3Rpb24gPSAxKSArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9IHJldihnZW5ldHJlZUNvbG9yJGNvbG9yKSksCiAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LDAuOCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYWxwaGEoImxpZ2h0Ymx1ZSIsMC41KSkpICsKICB5bGltKC0yLCA0NTAwKSArIGxhYnMoeSA9ICJQb3NpdGlvbiBpbiBzZXF1ZW5jZSIsIHggPSAiU2VxdWVuY2VzIiwgY29sb3IgPSAiTWVkaWFuIFRBTkdPIHNjb3JlIikgKyAKICBnZ3RpdGxlKCJUQU5HTyBoaXRzIHdpdGggSHlwaGFsX3JlZ19DV1AgZG9tYWluIG1hc2tlZCIpCmdnc2F2ZSgib3V0cHV0L2ZpZ3VyZS8yMDIxMDQyNS10YW5nby1zY29yZS1zZWdtZW50LnBuZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNikKYGBgCgojIyMgVGFuZGVtIHJlcGVhdCBzdHJ1Y3R1cmVzCgpUaGUgbm9uLU5URCBwb3J0aW9uIG9mIHRoZSBwcm90ZWlucyBldm9sdmUgcmFwaWRseSBhbmQgbWFueSBvZiB0aGVtIGNvbnRhaW4gdGFuZGVtIHJlcGVhdHMuIFRoZXJlZm9yZSwgY2hhcmFjdGVyaXppbmcgYW5kIHZpc3VhbGl6aW5nIHRoZSB0eXBlLCBudW1iZXIgYW5kIHNwYXRpYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSB0YW5kZW0gcmVwZWF0cyBzZXJ2ZSB0byBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2VzIGluIHRoZSBub24tTlREIHBhcnQgb2YgdGhlIHByb3RlaW5zIGluIHRoaXMgZmFtaWx5LgoKVG8gaWRlbnRpZnkgYW5kIGdyb3VwIHRhbmRlbSByZXBlYXRzLCBJIHVzZWQgW1hTVFJFQU1dKGh0dHBzOi8vYW1uZXdtYW5sYWIuc3RhbmZvcmQuZWR1L3hzdHJlYW0pIHdpdGggdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGBqYXZhIC1YbXgxMDAwbSAtWG1zMTAwMG0gLWphciB+L3N3L1hTVFJFQU0veHN0cmVhbS5qYXIgJGluIC1pLjcgLUkuNyAtZzMgLWUyIC1MMTUgLXogLUcgLU9gLiBUaGUgcGFyYW1ldGVycyB3ZXJlIGNob3NlbiB0byBpZGVudGlmeSBkZWdlbmVyYXRlIHRhbmRlbSByZXBlYXRzIHRoYXQgb2NjdXIgYXQgbGVhc3QgdHdvIHRpbWVzIGFuZCBtdXN0IGJlIGEgbWluaW11bSBsZW5ndGggb2YgNSBhLmEuIG9yIGxvbmdlciBhbmQgdGhlIG1pbmltdW0gbGVuZ3RoIG9mIGEgdGFuZGVtIHJlcGVhdCBkb21haW4gKD1wZXJpb2QgeCBjb3B5ICMpIG11c3QgYmUgZ3JlYXRlciB0aGFuIDE1IGEuYS4gUGxlYXNlIHNlZSBgc2NyaXB0L3hzdHJlYW0uc2hgIGZvciBleHBsYW5hdGlvbiBvZiB0aGUgcGFyYW1ldGVycy4KCmBgYHtyfQp0YW5kZW0gPC0gcmVhZF90c3YoIm91dHB1dC90YW5kZW0tcmVwZWF0cy9YU1RSRUFNX2NhdXJpc19vdXRncl9pMC43X2czX201X0wxNV9jaGFydC50c3YiLCAKICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9ICJjaWlpZmlkY2NjZCIpICU+JSAKICByZW5hbWUobmFtZSA9IGlkZW50aWZpZXIpICU+JSAKICBtdXRhdGUobmFtZSA9IG9yZGVyZWQobmFtZSwgbGV2ZWxzID0gcmV2KGdlbmV0cmVlT3JkZXIpKSkKIyBub3cgbGV0J3MgY3JlYXRlIGEgdGliYmxlIGZvciBwbG90dGluZywgd2hpY2ggd291bGQgY29udGFpbiBlYWNoIGluc3RhbmNlIG9mIHRoZSB0YW5kZW0gcmVwZWF0IG9uIGEgc2VwYXJhdGUgcm93CnRhbmRlbS5kaXYgPC0gdGFuZGVtICU+JSAKICByb3d3aXNlKG5hbWUpICU+JSAKICBzdW1tYXJpemUoZGl2ID0gbGlzdChjKHNlcShmcm9tID0gc3RhcnQsIHRvID0gZW5kLCBieSA9IHBlcmlvZCksIGVuZCkpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgdW5uZXN0KGRpdikKYGBgCgpgYGB7ciBwbG90X3RhbmRlbV9yZXBlYXRzLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD05fQojIHBsb3QKcmVxdWlyZShSQ29sb3JCcmV3ZXIpCm4uY29sID0gbmxldmVscyh0YW5kZW0kdHlwZSkKdHIuY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIlBhaXJlZCIpWzM6MTJdKShuLmNvbCkKcDEgPC0gZ2dwbG90KGZpbHRlcihmZWF0dXJlLCB0eXBlID09ICJlbnRpcmUgcHJvdGVpbiIpLCBhZXMoeCA9IGlkLCB5ID0gc3RhcnQpKSArIAogIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IGlkLCB5ZW5kID0gZW5kKSwgc2l6ZSA9IDIuNSwgY29sb3IgPSAiZ3JleTQwIikKcDIgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSB0YW5kZW0sIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsICB5ID0gc3RhcnQsIHllbmQgPSBlbmQsIGNvbG9yID0gdHlwZSwgdGV4dCA9IGNvbnNlbnN1c19ub2dhcCksIHNpemUgPSAyLjUsIGFscGhhID0gMC45KQpwMyA8LSBnZW9tX3NlZ21lbnQoZGF0YSA9IHRhbmRlbS5kaXYsIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsIHkgPSBkaXYsIHllbmQgPSBkaXYgKyAyKSwgc2l6ZSA9IDIuNSkKcDQgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSBmaWx0ZXIoZmVhdHVyZSwgdHlwZSA9PSAiSHlwaGFsX3JlZ19DV1AiKSwgYWVzKHggPSBpZCwgeSA9IHN0YXJ0LCB4ZW5kID0gaWQsIHllbmQgPSBlbmQpLCBjb2xvciA9ICIjMWY3OGI0Iiwgc2l6ZSA9IDIuNSkKcCA8LSBwMSArIHAyICsgcDMgKyBwNCArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ci5jb2wpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gcmV2KGdlbmV0cmVlQ29sb3IkY29sb3IpKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGFscGhhKCJsaWdodGJsdWUiLDAuNSkpKSArCiAgeWxpbSgtMiwgNDUwMCkgKyBsYWJzKHkgPSAiUG9zaXRpb24gaW4gc2VxdWVuY2UiLCB4ID0gIlNlcXVlbmNlcyIsIGNvbG9yID0gIk1lZGlhbiBUQU5HTyBzY29yZSIpICsgCiAgZ2d0aXRsZSgiVGFuZGVtIHJlcGVhdCBkb21haW5zIHdpdGggSHlwaGFsX3JlZ19DV1AgZG9tYWluIHNob3duIikKcApnZ3NhdmUoIm91dHB1dC9maWd1cmUvMjAyMTA1MDYtdGFuZGVtLXJlcGVhdHMucG5nIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQpgYGAKKipOb3RlKiogQmx1ZSBib3hlcyBpbmRpY2F0ZSB0aGUgUEYxMTc2NSBkb21haW5zIHdoaWxlIGFsbCBvdGhlciBub24tZ3JleSBib3hlcyBpbmRpY2F0ZSBYU1RSRUFNLWRldGVybWluZWQgdGFuZGVtIHJlcGVhdCBkb21haW5zLiBDb2xvcnMgYXJlIHVzZWQgdG8gZ3JvdXAgaGlnaGx5IHNpbWlsYXIgdGFuZGVtIHJlcGVhdHMuIFRoZSBibGFjayB0aGluIGxpbmVzIGRlbWFyY2F0ZSBhZGphY2VudCB0YW5kZW0gcmVwZWF0IHVuaXRzLiBUaGUgdGFibGUgYmVsb3cgc2hvd3MgdGhlIGNvcHkgbnVtYmVyLCBwZXJpb2QgYW5kIGNvbnNlbnN1cyBzZXF1ZW5jZSBmb3IgZWFjaCB0YW5kZW0gZG9tYWluIG9yZ2FuaXplZCBieSB0aGUgaG9zdCBzZXF1ZW5jZXMuCgpgYGB7cn0KRFQ6OmRhdGF0YWJsZSgKICB0YW5kZW0gJT4lIAogICAgcmVuYW1lKHNlcUwgPSBzZXFMZW5ndGgsIGVyciA9IGNvbnNlbnN1c19lcnJvciwgc2VxID0gY29uc2Vuc3VzX25vZ2FwKSAlPiUgCiAgICBzZWxlY3QoLXNlcUFsaWduLCAtdHlwZSwgLWNvbnNlbnN1c19nYXAsIC1zZXEsIHNlcSkgJT4lIAogICAgYXJyYW5nZShkZXNjKG5hbWUpKSwKICBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkKKQpgYGAKCmBgYHtyIHRyYW5zZm9ybV90YW5kZW1fZmVhdHVyZV9kYXRhfQojIGNvbWJpbmUgc2VxdWVuY2UgZmVhdHVyZXMgd2l0aCB0YW5kZW0gcmVwZWF0cwp0ci5mZWF0dXJlIDwtIHJiaW5kKAogIGZlYXR1cmUgJT4lIAogICAgZmlsdGVyKHR5cGUgJWluJSBjKCJlbnRpcmUgcHJvdGVpbiIsICJIeXBoYWxfcmVnX0NXUCIpLCApICU+JQogICAgbXV0YXRlKG5hbWUgPSBpZCwgdGlwID0gaWZlbHNlKHR5cGUgPT0gImVudGlyZSBwcm90ZWluIiwgYXMuY2hhcmFjdGVyKG5hbWUpLCAiUEYxMTc2NSIpKSAlPiUgCiAgICBzZWxlY3QobmFtZSwgdHlwZSwgc3RhcnQsIGVuZCwgdGlwKSwKICB0YW5kZW0gJT4lIG11dGF0ZSh0eXBlID0gcGFzdGUwKCJ0YW5kZW0iLCB0eXBlKSkgJT4lIHNlbGVjdChuYW1lLCB0eXBlLCBzdGFydCwgZW5kLCB0aXAgPSBjb25zZW5zdXNfbm9nYXApCikgJT4lIG11dGF0ZSh0eXBlID0gZHJvcGxldmVscyh0eXBlKSkKYGBgCgpgYGB7ciBwbG90bHlfdGFuZGVtX3JlcGVhdHMsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTl9CiMgcGxvdApyZXF1aXJlKFJDb2xvckJyZXdlcikKcmVxdWlyZShwbG90bHkpCm4uY29sID0gbmxldmVscyh0ci5mZWF0dXJlJHR5cGUpCnRyLmNvbCA8LSBjKCJncmV5NDAiLCAiIzFmNzhiNCIsIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIlBhaXJlZCIpWzM6MTJdKShuLmNvbC0yKSkKcDEgPC0gZ2dwbG90KHRyLmZlYXR1cmUsIGFlcyh4ID0gbmFtZSwgeSA9IHN0YXJ0LCB4ZW5kID0gbmFtZSwgeWVuZCA9IGVuZCwgY29sb3IgPSB0eXBlLCB0ZXh0ID0gdGlwKSkgKyAKICBnZW9tX3NlZ21lbnQoc2l6ZSA9IDIpCnAyIDwtIGdlb21fc2VnbWVudChzaXplID0gMiwgYWxwaGEgPSAwLjkpCnAgPC0gcDEgKyBwMiArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB0ci5jb2wpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gcmV2KGdlbmV0cmVlQ29sb3IkY29sb3IpKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGFscGhhKCJsaWdodGJsdWUiLDAuNSkpKSArCiAgeWxpbSgtMiwgNDUwMCkgKyBsYWJzKHkgPSAiUG9zaXRpb24gaW4gc2VxdWVuY2UiLCB4ID0gIlNlcXVlbmNlcyIsIGNvbG9yID0gIk1lZGlhbiBUQU5HTyBzY29yZSIpICsgCiAgZ2d0aXRsZSgiVGFuZGVtIHJlcGVhdCBkb21haW5zIHdpdGggSHlwaGFsX3JlZ19DV1AgZG9tYWluIHNob3duIikKZ2dwbG90bHkocCwgdG9vbHRpcCA9ICJ0ZXh0IikKYGBgCgo=